
/**
 * @fileoverview This is not a proper builder implementation, but for brevity's
 * sake it will have to suffice.
 *
 * Date: 2012/03/25
 * Time: 10:34 AM
 */


goog.provide('lfpug.builder.StoryBuilder');
goog.require('lfpug.model.Story');
goog.require('lfpug.model.Task');



/**
 * @constructor
 *
 * @param {lfpug.model.ArrayCollection} collection The collection of stories
 * this builder will manage.
 */
lfpug.builder.StoryBuilder = function(collection) {
  this.stories_ = collection;
  /**
   * @type {Object.<string, lfpug.model.Story>}
   * @private
   */
  this.allStories_ = {};
  /**
   * @type {Object.<string, lfpug.model.Task>}
   * @private
   */
  this.allTasks_ = {};
};


/**
 * To keep in the spirit of our real builder phase I will mimick the livecycle.
 */
lfpug.builder.StoryBuilder.prototype.startBuilder = function() {
  /**
   * @type {Object.<string, lfpug.model.Story>}
   * @private
   */
  this.storiesFound_ = {};
  /**
   * @type {Object.<string, lfpug.model.Task>}
   * @private
   */
  this.tasksFound_ = {};
};


/**
 * TODO WRITE UNIT TESTS FOR THIS!!
 * @private
 * @param {lfpug.model.BaseModel} obj Checks if an object went missing during
 * the last build cycle.
 * @return {boolean} is this object missing from the current build?
 */
lfpug.builder.StoryBuilder.prototype.objectMissing_ = function(obj) {
  if (obj instanceof lfpug.model.Story) {
    if (goog.isDefAndNotNull(this.storiesFound_[obj.getId()])) {
      return false;
    }
  } else {
    if (goog.isDefAndNotNull(this.tasksFound_[obj.getId()])) {
      return false;
    }
  }
  return true;
};


/**
 * To keep in the spirit of our real builder phase I will mimick the livecycle.
 * FinishBuilder manages items which have been removed from the data coming in.
 */
lfpug.builder.StoryBuilder.prototype.finishBuilder = function() {
  var storiesSrc = /** @type {Array.<lfpug.model.Story>} */
      (this.stories_.getSource());
  var index = storiesSrc.length;
  while (index--) {
    var story = storiesSrc[index];
    if (this.objectMissing_(story)) {
      this.stories_.removeItemAt(index);
      var tasks = story.getTasks();
      //remove all the associated tasks
      var tasksSrc = tasks.getSource();
      var subIndex = tasksSrc.length;
      while (subIndex--) {
        var task = tasksSrc[subIndex];
        delete this.allTasks_[task.getId()];
      }
      story.dispose();
      delete this.allStories_[story.getId()];

    } else {
      var tasks = story.getTasks();
      var tasksSrc = tasks.getSource();
      var subIndex = tasksSrc.length;
      while (subIndex--) {
        var task = tasksSrc[subIndex];
        if (this.objectMissing_(task)) {
          tasks.removeItemAt(subIndex);
          task.dispose();
          delete this.allTasks_[task.getId()];
        }
      }
    }
  }
};


/**
 * Gets the story from the hash or creates a new one.
 * @param {string} id The id of story you are asking the builder for.
 * @return {lfpug.model.Story} The story you asked the builder for.
 */
lfpug.builder.StoryBuilder.prototype.createStory = function(id) {
  if (id in this.allStories_) {
    return this.allStories_[id];
  }
  return new lfpug.model.Story(id);
};


/**
 * commitStory makes the story visible to the current live cycle of the builder.
 * @param {lfpug.model.Story} story The story you wish to commit into the
 * builder.
 */
lfpug.builder.StoryBuilder.prototype.commitStory = function(story) {
  var id = story.getId();
  this.allStories_[id] = story;
  this.storiesFound_[id] = story;
  if (!goog.array.contains(this.stories_.getSource(), story)) {
    this.stories_.addItem(story);
  }
};


/**
 * Gets the task from the hash or creates a new one.
 * @param {string} id The id of task you are asking the builder for.
 * @return {lfpug.model.Task} The task you asked the builder for.
 */
lfpug.builder.StoryBuilder.prototype.createTask = function(id) {
  if (id in this.allTasks_) {
    return this.allTasks_[id];
  }
  return new lfpug.model.Task(id);
};


/**
 * commitTask makes the task visible to the current live cycle of the builder.
 * @param {lfpug.model.Story} story The story the task is associated with.
 * @param {lfpug.model.Task} task The task you wish to commit into the
 * builder.
 */
lfpug.builder.StoryBuilder.prototype.commitTask = function(story, task) {
  var id = task.getId();
  this.allTasks_[id] = task;
  this.tasksFound_[id] = task;
  var tasks = story.getTasks();
  if (!goog.array.contains(tasks.getSource(), task)) {
    tasks.addItem(task);
  }
};
